<template>
    <div class="map-wrapper">
        <div id="container"></div>
        <div class="map-utils-layers">
            <Checkbox
                v-model="layerDisplay.satellite"
                @on-change="routeMapLayer('satellite')"
                >卫星图</Checkbox
            >
            <Checkbox
                v-model="layerDisplay.roadnet"
                @on-change="routeMapLayer('roadnet')"
                >路网图</Checkbox
            >
            <Checkbox
                v-model="layerDisplay.traffic"
                @on-change="routeMapLayer('traffic')"
                >实时路况</Checkbox
            >
            <Checkbox
                v-model="layerDisplay.building"
                @on-change="routeMapLayer('building')"
                >建筑楼块</Checkbox
            >
            <input
                type="text"
                id="map-search"
                class="map-utils-textbox"
                placeholder="输入关键字快速定位区域"
            />
        </div>
        <div id="mask" v-show="maskOn"></div>
    </div>
</template>

<script>
    import { busEventEmit, busEventHandle } from "@/teleport/bus";
    import jsonDownloader from "@/libs/exportJSON";
    import config from "@/config/global";

    export default {
        name: "",
        data() {
            return {
                map: null,
                maskOn: false,
                layers: {
                    satellite: null,
                    roadnet: null,
                    traffic: null,
                    building: null,
                },
                layerDisplay: {
                    satellite: false,
                    roadnet: false,
                    traffic: false,
                    building: false,
                },
                mouseTool: null,
                counter: {
                    pin: 0,
                    rect: 0,
                },
                mouseDrawMode: null,
                polyEditor: null,
                heatpin: require("@/assets/images/dd.png"),
                heatpinActive: require("@/assets/images/dd-via.png"),
                eventHandler: {
                    click: null,
                    pathedit: null,
                    rangeedit: null,
                    searchedSelect: null,
                },
                placeSearch: null,
            };
        },
        mounted() {
            this.initAMap();
            this.registerMapEvent();
            this.listenDrawRequestEvent();
            this.listenCoverageDataCompleteEvent();
            this.listenCoverageRemoveEvent();
        },
        methods: {
            initAMap() {
                this.map = new AMap.Map("container", {
                    mapStyle: "amap://styles/macaron",
                    zoom: 12,
                });
                store.heatmapHistory = new Array();
                AMap.plugin(
                    [
                        "AMap.MouseTool",
                        "AMap.ToolBar",
                        "AMap.Driving",
                        "AMap.Autocomplete",
                        "AMap.PlaceSearch",
                        "AMap.PolyEditor",
                        "AMap.CircleEditor",
                        "AMap.RangingTool",
                        "AMap.Heatmap",
                    ],
                    (e) => {
                        this.initAMapMouseTool();
                        this.listenPOIDrawEvent();
                    }
                );
                this.initAvailableLayer();
                this.initAMapSearchService();
            },
            listenDrawRequestEvent() {
                const $this = this;
                busEventHandle("heatmap-pin-draw-request", () => {
                    $this.mouseTool.close();
                    $this.mouseTool.circle();
                    $this.mouseDrawMode = "pin";
                });
                busEventHandle("heatmap-pin-draw-cancel", () => {
                    $this.mouseTool.close();
                });
                busEventHandle("heatmap-rect-draw-request", () => {
                    $this.mouseTool.close();
                    $this.mouseTool.polygon();
                    $this.mouseDrawMode = "rect";
                });
                busEventHandle("heatmap-rect-draw-cancel", () => {
                    $this.mouseTool.close();
                });
            },
            calculateColorByValue(value) {
                let s = 1;
                let l = 0.4;
                //0~30之间，最大值为红色，即h=0，最小值为绿色，即h=100
                let min = parseInt(store.heatmapConfig.min);
                let max = parseInt(store.heatmapConfig.max);
                let h = (1 - (value / max))/3.6;
                let colorString = this.hslToHex(h, s, l);
                return colorString;
            },
            hslToHex(h, s, l) {
                var r, g, b;
                if (s == 0) {
                    r = g = b = l; // achromatic
                } else {
                    var hue2rgb = function hue2rgb(p, q, t) {
                        if (t < 0) t += 1;
                        if (t > 1) t -= 1;
                        if (t < 1 / 6) return p + (q - p) * 6 * t;
                        if (t < 1 / 2) return q;
                        if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
                        return p;
                    };

                    var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                    var p = 2 * l - q;
                    r = hue2rgb(p, q, h + 1 / 3);
                    g = hue2rgb(p, q, h);
                    b = hue2rgb(p, q, h - 1 / 3);
                }
                let rgbValue = [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
                return "#" + ((1 << 24) + (rgbValue[0] << 16) + (rgbValue[1] << 8) + rgbValue[2]).toString(16).slice(1);
            },
            listenCoverageDataCompleteEvent() {
                const $this = this;
                busEventHandle("heatmap-pin-data-complete", (msg) => {
                    const circle = store.latestDrawn;
                    circle.setExtData(msg);
                    //TODO: 在画好热力图区域，并填写完表单的时候，一定要初始化store.heatmapConfig
                    circle.setRadius(store.heatmapConfig.radius);
                    circle.setOptions({
                        strokeColor: $this.calculateColorByValue(msg.value),
                        strokeOpacity: 1,
                        strokeWeight: 10,
                        strokeStyle: "dashed",
                        fillColor: $this.calculateColorByValue(msg.value),
                        fillOpacity: 0.6,
                    });
                    $this.polyEditor = null;
                    $this.maskOn = false;
                    //TODO:
                    //更新热力图，如果基础配置还没做好，则按照默认的配置渲染热力图
                });
                busEventHandle("heatmap-pin-data-mutanted", (msg) => {
                    const circle = store.heatmapHistory.find((e) => {
                        return e.getExtData().id === msg.id;
                    });
                    $this.polyEditor.close();
                    circle.setExtData(msg);
                    circle.setOptions({
                        strokeColor: $this.calculateColorByValue(msg.value),
                        strokeOpacity: 1,
                        strokeWeight: 10,
                        strokeStyle: "dashed",
                        fillColor: $this.calculateColorByValue(msg.value),
                        fillOpacity: 0.6,
                    });
                    circle.w.clickable = true;
                    this.maskOn = false;
                });
                busEventHandle("heatmap-rect-data-complete", (msg) => {
                    const polygon = store.latestDrawn;
                    debugger
                    polygon.setExtData(msg);
                    polygon.setOptions({
                        strokeColor: "#000000",
                        strokeOpacity: 1,
                        strokeWeight: 4,
                        strokeStyle: "dashed",
                        fillColor: "#000000",
                        fillOpacity: 0,
                    });
                    store.heatmapConfig = {
                      radius:parseFloat(msg.diameter),
                      min:parseFloat(msg.range.split(',')[0]),
                      max:parseFloat(msg.range.split(',')[1])
                    }
                    $this.maskOn = false;
                });
                busEventHandle("heatmap-rect-data-mutanted", (msg) => {
                    const polygon = store.heatmapHistory.find((e) => {
                        return e.getExtData().id === msg.id;
                    });
                    $this.polyEditor.close();
                    polygon.setExtData(msg);
                    polygon.setOptions({
                        strokeColor: "#ffffff",
                        strokeOpacity: 1,
                        strokeWeight: 10,
                        strokeStyle: "dashed",
                        fillColor: "#ffffff",
                        fillOpacity: 0,
                    });
                    store.heatmapConfig = {
                      radius:parseFloat(msg.diameter),
                      min:parseFloat(msg.range.split(',')[0]),
                      max:parseFloat(msg.range.split(',')[1])
                    }
                    polygon.setClickable(true);
                    $this.maskOn = false;
                });
            },
            updateHeatMap() {},
            listenCoverageRemoveEvent() {
                busEventHandle("delete-pin", (msg) => {
                    const pin = store.drawHistory.find((e) => {
                        return e.getExtData().id === msg;
                    });
                    store.heatmapHistory = store.heatmapHistory.filter((e) => {
                        return e.getExtData().id !== msg;
                    });
                    pin.setMap(null);
                });
                busEventHandle("delete-rect", (msg) => {
                    const rect = store.heatmapHistory.find((e) => {
                        return e.getExtData().id === msg;
                    });
                    store.heatmapHistory = store.heatmapHistory.filter((e) => {
                        return e.getExtData().id !== msg;
                    });
                    rect.setMap(null);
                });
            },
            initAvailableLayer() {
                this.layers.satellite = new AMap.TileLayer.Satellite({
                    zooms: [1, 30],
                    opacity: 1,
                    visibile: true,
                    zIndex: 4,
                });
                this.layers.roadnet = new AMap.TileLayer.RoadNet({
                    zooms: [1, 30],
                    opacity: 1,
                    visibile: true,
                    zIndex: 8,
                });
                this.layers.traffic = new AMap.TileLayer.Traffic({
                    zooms: [1, 30],
                    zIndex: 10,
                });
                this.layers.building = new AMap.Buildings({
                    zooms: [1, 30],
                    zIndex: 9,
                });
            },
            initAMapMouseTool() {
                this.mouseTool = new AMap.MouseTool(this.map);
                const $this = this;
                this.mouseTool.on("draw", (e) => {
                    //遮住地图区域和左侧工具栏，防止表单完善数据前继续插入
                    switch ($this.mouseDrawMode) {
                        case "pin":
                            $this.emitPinDrawnEvent(e);
                            break;
                        case "rect":
                            $this.emitRectDrawnEvent(e);
                            break;
                    }
                });
            },
            emitPinDrawnEvent(e) {
                const $this = this;
                $this.maskOn = true;
                if (e.obj.CLASS_NAME === "AMap.Circle") {
                    store.heatmapHistory.push(e.obj);
                    $this.listenClickEvent(e.obj);
                    $this.listenDragEvent(e.obj);
                    store.latestDrawn = e.obj;
                    busEventEmit("pin-drawn", {
                        id: e.obj._amap_id,
                        coord: `${e.obj.getCenter().lng},${e.obj.getCenter().lat}`,
                    });
                    $this.counter.poi++;
                }
            },
            emitRectDrawnEvent(e) {
                const $this = this;
                $this.maskOn = true;
                if (e.obj.CLASS_NAME === "AMap.Polygon") {
                    store.heatmapHistory.push(e.obj);
                    $this.listenClickEvent(e.obj);
                    store.latestDrawn = e.obj;
                    busEventEmit("rect-drawn", {
                        id: e.obj._amap_id,
                        area: {
                            lt: `${e.obj.getPath()[0].lng},${
                                e.obj.getPath()[0].lat
                            }`,
                            rt: `${e.obj.getPath()[1].lng},${
                                e.obj.getPath()[1].lat
                            }`,
                            rb: `${e.obj.getPath()[2].lng},${
                                e.obj.getPath()[2].lat
                            }`,
                            lb: `${e.obj.getPath()[3].lng},${
                                e.obj.getPath()[3].lat
                            }`,
                        },
                    });
                    $this.counter.range++;
                }
            },
            initAMapSearchService() {
                let autoOptions = {
                    input: "map-search",
                };
                let autoService = new AMap.Autocomplete(autoOptions);
                const select = (e) => {
                    this.placeSearch.setCity(e.poi.adcode);
                    this.placeSearch.search(e.poi.name); //关键字查询查询
                };
                this.placeSearch = new AMap.PlaceSearch({
                    map: this.map,
                });
                this.placeSearch.on("markerClick", this.eventHandler.click);
                AMap.event.addListener(autoService, "select", select); //注册监听，当选中某条记录时会触发
            },
            routeMapLayer(name) {
                if (this.layerDisplay[name]) {
                    this.layers[name].setMap(this.map);
                } else {
                    this.layers[name].setMap(null);
                }
            },
            updateCoverageAppearance(coverage) {
                let thisOne = coverage;
                let others = null;
                switch (coverage.CLASS_NAME) {
                    case "AMap.Circle":
                        thisOne = coverage;
                        thisOne.setOptions({
                            strokeStyle: "solid",
                        });
                        others = store.heatmapHistory.filter((e) => {
                            return (
                                e.getExtData().id !== coverage.getExtData().id &&
                                e.CLASS_NAME === "AMap.Circle"
                            );
                        });
                        if (others) {
                            others.forEach((o) => {
                                o.setOptions({
                                    strokeStyle: "dashed",
                                });
                            });
                        }
                        break;
                    case "AMap.Polygon":
                        thisOne = coverage;
                        thisOne.setOptions({
                            strokeStyle: "solid",
                        });
                        others = store.heatmapHistory.filter((e) => {
                            return (
                                e.getExtData().id !== coverage.getExtData().id &&
                                e.CLASS_NAME === "AMap.Polygon"
                            );
                        });
                        if (others) {
                            others.forEach((o) => {
                                o.setOptions({
                                    strokeStyle: "dashed",
                                });
                            });
                        }
                        break;
                }
            },
            registerMapEvent() {
                const $this = this;
                this.eventHandler.click = (event) => {
                    let targetCoverage = event.target;
                    console.dir(targetCoverage);
                    switch (targetCoverage.CLASS_NAME) {
                        case "AMap.Circle":
                            if ($this.mouseDrawMode === "pin") {
                                let id = targetCoverage.getExtData().id;
                                $this.polyEditor = new AMap.CircleEditor(
                                    $this.map,
                                    targetCoverage
                                );
                                $this.polyEditor.open();
                                $this.listenPolyEditEvent(targetCoverage, "effect");
                                targetCoverage.w.clickable = false;
                                busEventEmit("pin-edit", {
                                    ...targetCoverage.getExtData(),
                                    coord: `${targetCoverage.getCenter().lng},${
                                        targetCoverage.getCenter().lat
                                    }`
                                });
                                $this.updateCoverageAppearance(targetCoverage);
                            }
                            break;
                        case "AMap.Polygon":
                            if ($this.mouseDrawMode === "rect") {
                                let id = targetCoverage.getExtData().id;
                                if (targetCoverage.w.clickable) {
                                    $this.polyEditor = new AMap.PolyEditor(
                                        $this.map,
                                        targetCoverage
                                    );
                                    $this.polyEditor.open();
                                    $this.listenPolyEditEvent(
                                        targetCoverage,
                                        "rect"
                                    );
                                    targetCoverage.w.clickable = false;
                                    busEventEmit("rect-edit", {
                                        ...targetCoverage.getExtData(),
                                        area: {
                                            lt: `${
                                                targetCoverage.getPath()[0].lng
                                            },${targetCoverage.getPath()[0].lat}`,
                                            rt: `${
                                                targetCoverage.getPath()[1].lng
                                            },${targetCoverage.getPath()[1].lat}`,
                                            rb: `${
                                                targetCoverage.getPath()[2].lng
                                            },${targetCoverage.getPath()[2].lat}`,
                                            lb: `${
                                                targetCoverage.getPath()[3].lng
                                            },${targetCoverage.getPath()[3].lat}`,
                                        },
                                    });
                                    $this.updateCoverageAppearance(targetCoverage);
                                }
                            }
                            break;
                    }
                };
                this.eventHandler.searchedSelect = (event) => {
                    debugger;
                };
                if (store.heatmapHistory) {
                    if (store.heatmapHistory.length > 0) {
                        this.dispatchClickEvent();
                        this.restoreClickEvent();
                    }
                }
            },
            listenClickEvent(coverage) {
                coverage.on("click", this.eventHandler.click);
            },
            dispatchClickEvent() {
                const eventHandler = this.eventHandler.click;
                switch (this.mouseDrawMode) {
                    case "pin":
                        store.heatmapHistory
                            .filter((e) => {
                                return e.CLASS_NAME !== "AMap.Circle";
                            })
                            .forEach((o) => {
                                o.off("click", eventHandler);
                            });
                        this.mouseTool.close();
                        break;
                    case "rect":
                        store.heatmapHistory
                            .filter((e) => {
                                return e.CLASS_NAME !== "AMap.Polygon";
                            })
                            .forEach((o) => {
                                o.off("click", eventHandler);
                            });
                        this.mouseTool.close();
                        break;
                }
            },
            restoreClickEvent() {
                const eventHandler = this.eventHandler.click;
                const $this = this;
                switch (this.mouseDrawMode) {
                    case "pin":
                        store.heatmapHistory
                            .filter((e) => {
                                return e.CLASS_NAME === "AMap.Circle";
                            })
                            .forEach((o) => {
                                $this.listenClickEvent(o);
                            });
                        break;
                    case "rect":
                        store.heatmapHistory
                            .filter((e) => {
                                return e.CLASS_NAME === "AMap.Polygon";
                            })
                            .forEach((o) => {
                                $this.listenClickEvent(o);
                            });
                        break;
                }
            },
            listenPolyEditEvent(targetCoverage, type) {
                this.eventHandler.pathedit = (event) => {
                    switch (type) {
                        case "rect":
                            busEventEmit("rect-edit", {
                                ...targetCoverage.getExtData(),
                                area: {
                                    lt: `${targetCoverage.getPath()[0].lng},${
                                        targetCoverage.getPath()[0].lat
                                    }`,
                                    rt: `${targetCoverage.getPath()[1].lng},${
                                        targetCoverage.getPath()[1].lat
                                    }`,
                                    rb: `${targetCoverage.getPath()[2].lng},${
                                        targetCoverage.getPath()[2].lat
                                    }`,
                                    lb: `${targetCoverage.getPath()[3].lng},${
                                        targetCoverage.getPath()[3].lat
                                    }`,
                                },
                            });
                            break;
                    }
                };
                if (type === "effect") {
                    this.polyEditor.on("move", this.eventHandler.pathedit);
                    this.polyEditor.on("adjust", this.eventHandler.pathedit);
                } else {
                    this.polyEditor.on("addnode", this.eventHandler.pathedit);
                    this.polyEditor.on("adjust", this.eventHandler.pathedit);
                    this.polyEditor.on("removenode", this.eventHandler.pathedit);
                }
            },
            listenDragEvent(coverage) {
                coverage.on("dragend", (event) => {
                    let targetCoverage = event.target;
                    this.updateCoverageAppearance(coverage);
                    switch (targetCoverage.CLASS_NAME) {
                        case "AMap.Polygon":
                            busEventEmit("rect-edit", {
                                id: targetCoverage.getExtData().id,
                                area: {
                                    lt: `${targetCoverage.getPath()[0].lng},${
                                        targetCoverage.getPath()[0].lat
                                    }`,
                                    rt: `${targetCoverage.getPath()[1].lng},${
                                        targetCoverage.getPath()[1].lat
                                    }`,
                                    rb: `${targetCoverage.getPath()[2].lng},${
                                        targetCoverage.getPath()[2].lat
                                    }`,
                                    lb: `${targetCoverage.getPath()[3].lng},${
                                        targetCoverage.getPath()[3].lat
                                    }`,
                                },
                            });
                            break;
                    }
                });
            },
        },
    };
</script>

<style scoped>
    #mask {
        position: fixed;
        background: #00000044;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 99;
    }
    #container {
        width: 100vw;
        height: 100vh;
        position: fixed;
        z-index: 0;
    }
    .map-utils-layers {
        display: flex;
        flex-flow: row nowrap;
        align-items: center;
        position: fixed;
        left: 64px;
        bottom: 16px;
        background: #fff;
        padding: 16px;
        border-radius: 6px;
        box-shadow: 0 3px 3px #00000055;
    }
    .map-utils-textbox {
        border-radius: 5px;
        border: 1px #d1d4df solid;
        width: 275px;
        padding: 5px;
        font-size: 12px;
        margin: 0 12px;
    }
    .marker-label {
        background: #000000aa;
        color: #fff;
        border: 1px #000 solid;
        border-radius: 2px;
    }
</style>